package Engine.Character;

import java.io.IOException;
import javax.microedition.lcdui.Image;

/**
 * Model class for the enemies. It has the corresponding sequences of movement and attack.
 * @author Gerardo Galíndez
 */
public class EnemyCharacter extends Character {

    //---------------------------------------------------------
    //Movement sequences---------------------------------------
    private int[] standSequence = {0,1};
    private int[] movementSequence = {2};
    private int[] attackSequence = {3,4};
    private int[] retreatSequence = {5};
    private int[] currentSequence;
    //Types of enemies-----------------------------------------
    /**
     * Array of enemy corresponding of one type
     */
    public static final char[] oneEnemyTypes = {EnemyCharacter.ATHOS,EnemyCharacter.BASILISK,EnemyCharacter.BUG_BEAR,EnemyCharacter.CARM,EnemyCharacter.DRAGON,EnemyCharacter.GARGOYLE_FIRE,EnemyCharacter.GARGOYLE_WIND,EnemyCharacter.GOLEM,EnemyCharacter.HUMUS,EnemyCharacter.MALBORO,EnemyCharacter.MIMIC_FIRE,EnemyCharacter.MIMIC_WATER,EnemyCharacter.OGRE_EARTH,EnemyCharacter.OGRE_FIRE,EnemyCharacter.PALADIN,EnemyCharacter.POLTERGEIST_FIRE,EnemyCharacter.POLTERGEIST_WIND,EnemyCharacter.SIREN,EnemyCharacter.ZOMBIE};
    /**
     * Array of enemy corresponding of two types
     */
    public static final char[] twoEnemiesTypes = {EnemyCharacter.ATHOS,EnemyCharacter.BASILISK,EnemyCharacter.BUG_BEAR,EnemyCharacter.CARM,EnemyCharacter.GARGOYLE_FIRE,EnemyCharacter.GARGOYLE_WIND,EnemyCharacter.HUMUS,EnemyCharacter.MALBORO,EnemyCharacter.MIMIC_FIRE,EnemyCharacter.MIMIC_WATER,EnemyCharacter.OGRE_EARTH,EnemyCharacter.OGRE_FIRE,EnemyCharacter.SIREN,EnemyCharacter.ZOMBIE};
    /**
     * Array of enemy corresponding of three types
     */
    public static final char[] threeEnemiesTypes = {EnemyCharacter.MALBORO,EnemyCharacter.MIMIC_FIRE,EnemyCharacter.MIMIC_WATER,EnemyCharacter.OGRE_EARTH,EnemyCharacter.OGRE_FIRE,EnemyCharacter.ZOMBIE};
    //Counter of the frames for movement-----------------------
    private int movementCounter;
    //Maximum number of frames per sequence--------------------
    private final int FRAME_LIMITER = 9;
    //Code of each enemy---------------------------------------
    private final char enemyCode;
    /**
     *Quantity of the enemies type one
     */
    public static final int ONE_ENEMY_TYPES_QUANTITY = 19;
    /**
     * Quantity of the enemies type two
     */
    public static final int TWO_ENEMY_TYPES_QUANTITY = 14;
    /**
     * Quantity of the enemies type three
     */
    public static final int THREE_ENEMY_TYPES_QUANTITY = 6;
    /**
     *Char representing Athos character
     */
    public static final char ATHOS = 'a';
    /**
     *Char representing Basilisk character
     */
    public static final char BASILISK = 'b';
    /**
     *Char representing Bug Bear character
     */
    public static final char BUG_BEAR = 'c';
    /**
     *Char representing Carm character
     */
    public static final char CARM = 'd';
    /**
     *Char representing Dragon character
     */
    public static final char DRAGON = 'e';
    /**
     *Char representing Gargoyle Fire character
     */
    public static final char GARGOYLE_FIRE = 'f';
    /**
     *Char representing Gargoyle Wind character
     */
    public static final char GARGOYLE_WIND = 'g';
    /**
     *Char representing Golem character
     */
    public static final char GOLEM = 'h';
    /**
     *Char representing Humus character
     */
    public static final char HUMUS = 'i';
    /**
     *Char representing Malboro character
     */
    public static final char MALBORO = 'j';
    /**
     *Char representing Mimic Fire character
     */
    public static final char MIMIC_FIRE = 'k';
    /**
     *Char representing Mimic Water character
     */
    public static final char MIMIC_WATER = 'l';
    /**
     *Char representing Ogre Earth character
     */
    public static final char OGRE_EARTH = 'm';
    /**
     *Char representing Ogre Fire character
     */
    public static final char OGRE_FIRE = 'n';
    /**
     *Char representing Paladin character
     */
    public static final char PALADIN = 'o';
    /**
     *Char representing Poltergeist Fire character
     */
    public static final char POLTERGEIST_FIRE = 'p';
    /**
     *Char representing Poltergeist Wind character
     */
    public static final char POLTERGEIST_WIND = 'q';
    /**
     *Char representing Siren character
     */
    public static final char SIREN = 'r';
    /**
     *Char representing Zombie character
     */
    public static final char ZOMBIE = 's';
    
    /**
     * Creates an Enemy Character with an image, the frame dimensions and an element
     * @param enemyCode
     */
    public EnemyCharacter(char enemyCode) {
        super(EnemyCharacter.getImage(enemyCode), getEnemiesWidth(enemyCode), getEnemiesHeight(enemyCode), getElement(enemyCode));
        this.movementCounter = 0;
        this.setFrameSequence(this.standSequence);
        this.setFrame(0);
        this.enemyCode = enemyCode;
        super.setCurrentHealthPoints(50);
        super.setPhysicalAttack(10);
        super.setPhysicalDefense(5);
    }

    /**
     * Creates a Boss Enemy Character with an image, the frame dimensions and an element
     * @param bossImage
     * @param frameWidth
     * @param frameHeight
     * @param element
     */
    public EnemyCharacter(Image bossImage, int frameWidth, int frameHeight, int element) {
        super(bossImage, frameWidth, frameHeight, element);
        this.enemyCode = 0;
    }

    /**
     * Creates one enemy with the One Enemy Types
     * @param enemyCode
     * @return an enemy ubicated in the enemyCode place
     */
    public EnemyCharacter createOneEnemy(int enemyCode) {
        return new EnemyCharacter(oneEnemyTypes[enemyCode]);
    }

    /**
     * Creates two enemies with the Two Enemy Types
     * @param enemyCode
     * @return an enemy ubicated in the enemyCode place
     */
    public EnemyCharacter createTwoEnemies(int enemyCode) {
        return new EnemyCharacter(twoEnemiesTypes[enemyCode]);
    }

    /**
     * Creates three enemies with the Three Enemy Types
     * @param enemyCode
     * @return an enemy ubicated in the enemyCode place
     */
    public EnemyCharacter createThreeEnemies(int enemyCode) {
        return new EnemyCharacter(threeEnemiesTypes[enemyCode]);
    }

    //Gets the image of each enemy
    private static Image getImage(char enemyCode) {
        try {
            switch (enemyCode) {
                case ATHOS:
                    return Image.createImage("/Images/Enemies/Athos.png");
                case BASILISK:
                    return Image.createImage("/Images/Enemies/Basilisk.png");
                case BUG_BEAR:
                    return Image.createImage("/Images/Enemies/BugBear.png");
                case CARM:
                    return Image.createImage("/Images/Enemies/Carm.png");
                case DRAGON:
                    return Image.createImage("/Images/Enemies/Dragon.png");
                case GARGOYLE_FIRE:
                    return Image.createImage("/Images/Enemies/Gargoyle-Fire.png");
                case GARGOYLE_WIND:
                    return Image.createImage("/Images/Enemies/Gargoyle-Wind.png");
                case GOLEM:
                    return Image.createImage("/Images/Enemies/Golem.png");
                case HUMUS:
                    return Image.createImage("/Images/Enemies/Humus.png");
                case MALBORO:
                    return Image.createImage("/Images/Enemies/Malboro.png");
                case MIMIC_FIRE:
                    return Image.createImage("/Images/Enemies/Mimic-Fire.png");
                case MIMIC_WATER:
                    return Image.createImage("/Images/Enemies/Mimic-Water.png");
                case OGRE_FIRE:
                    return Image.createImage("/Images/Enemies/Ogre-Fire.png");
                case OGRE_EARTH:
                    return Image.createImage("/Images/Enemies/Ogre-Earth.png");
                case PALADIN:
                    return Image.createImage("/Images/Enemies/Paladin.png");
                case POLTERGEIST_FIRE:
                    return Image.createImage("/Images/Enemies/Poltergeist-Fire.png");
                case POLTERGEIST_WIND:
                    return Image.createImage("/Images/Enemies/Poltergeist-Wind.png");
                case SIREN:
                    return Image.createImage("/Images/Enemies/Siren.png");
                case ZOMBIE:
                    return Image.createImage("/Images/Enemies/Zombie.png");
                default:
                    System.out.println("Incorrect enemy code at getImage().");
                    return null;
            }
        } catch(IOException ioex) {
            ioex.printStackTrace();
            return null;
        }
    }

    /**
     * Return the experience points after a battle
     * @param enemyCode type of enemy
     * @return the experience code given by the enemy
     */
    public static int getExperiencePoints(char enemyCode) {
        switch (enemyCode) {
            case ATHOS:
                return 2;
            case BASILISK:
                return 3;
            case BUG_BEAR:
                return 5;
            case CARM:
                return 3;
            case DRAGON:
                return 7;
            case GARGOYLE_FIRE:
                return 4;
            case GARGOYLE_WIND:
                return 7;
            case GOLEM:
                return 3;
            case HUMUS:
                return 1;
            case MALBORO:
                return 5;
            case MIMIC_FIRE:
                return 7;
            case MIMIC_WATER:
                return 4;
            case OGRE_FIRE:
                return 9;
            case OGRE_EARTH:
                return 5;
            case PALADIN:
                return 5;
            case POLTERGEIST_FIRE:
                return 7;
            case POLTERGEIST_WIND:
                return 4;
            case SIREN:
                return 8;
            case ZOMBIE:
                return 10;
            default:
                System.out.println("Incorrect enemy code at getExperiencePonits().");
                return -1;
        }
    }
    
    //Gets the width of each enemy
    private static int getEnemiesWidth(char enemyCode) {
        switch (enemyCode) {
                case ATHOS:
                    return 73;
                case BASILISK:
                    return 65;
                case BUG_BEAR:
                    return 65;
                case CARM:
                    return 94;
                case DRAGON:
                    return 105;
                case GARGOYLE_FIRE:
                    return 53;
                case GARGOYLE_WIND:
                    return 53;
                case GOLEM:
                    return 94;
                case HUMUS:
                    return 50;
                case MALBORO:
                    return 40;
                case MIMIC_FIRE:
                    return 61;
                case MIMIC_WATER:
                    return 61;
                case OGRE_FIRE:
                    return 66;
                case OGRE_EARTH:
                    return 66;
                case PALADIN:
                    return 70;
                case POLTERGEIST_FIRE:
                    return 62;
                case POLTERGEIST_WIND:
                    return 62;
                case SIREN:
                    return 45;
                case ZOMBIE:
                    return 50;
                default:
                    System.out.println("Incorrect enemy code at getEnemiesWidth.");
                    return -1;
            }
    }

    //Gets the height of each enemy
    private static int getEnemiesHeight(char enemyCode) {
        switch (enemyCode) {
                case ATHOS:
                    return 66;
                case BASILISK:
                    return 75;
                case BUG_BEAR:
                    return 55;
                case CARM:
                    return 54;
                case DRAGON:
                    return 104;
                case GARGOYLE_FIRE:
                    return 70;
                case GARGOYLE_WIND:
                    return 70;
                case GOLEM:
                    return 72;
                case HUMUS:
                    return 64;
                case MALBORO:
                    return 40;
                case MIMIC_FIRE:
                    return 42;
                case MIMIC_WATER:
                    return 42;
                case OGRE_FIRE:
                    return 87;
                case OGRE_EARTH:
                    return 87;
                case PALADIN:
                    return 61;
                case POLTERGEIST_FIRE:
                    return 85;
                case POLTERGEIST_WIND:
                    return 85;
                case SIREN:
                    return 72;
                case ZOMBIE:
                    return 54;
                default:
                    System.out.println("Incorrect enemy code at getEnemiesWidth.");
                    return -1;
            }
    }

    //Gets the element of each enemy
    //Fire 6
    //Earth 6
    //Wind 5
    //Water 2
    private static int getElement(char enemyCode) {
         switch (enemyCode) {
                case ATHOS:
                    return WIND;
                case BASILISK:
                    return FIRE;
                case BUG_BEAR:
                    return EARTH;
                case CARM:
                    return FIRE;
                case DRAGON:
                    return EARTH;
                case GARGOYLE_FIRE:
                    return FIRE;
                case GARGOYLE_WIND:
                    return WIND;
                case GOLEM:
                    return EARTH;
                case HUMUS:
                    return WIND;
                case MALBORO:
                    return WATER;
                case MIMIC_FIRE:
                    return FIRE;
                case MIMIC_WATER:
                    return WATER;
                case OGRE_FIRE:
                    return FIRE;
                case OGRE_EARTH:
                    return EARTH;
                case PALADIN:
                    return EARTH;
                case POLTERGEIST_FIRE:
                    return FIRE;
                case POLTERGEIST_WIND:
                    return WIND;
                case SIREN:
                    return WIND;
                case ZOMBIE:
                    return EARTH;
                default:
                    System.out.println("Incorrect enemy code at getEnemiesWidth.");
                    return -1;
            }
    }

    /**
     * Gets the enemy code
     * @return enemy Code
     */
    public char getEnemyCode() {
        return enemyCode;
    }

    /**
     * Changes the sequence to stand
     */
    public void stand() {
        if (currentSequence != this.standSequence) {
            this.setFrameSequence(this.standSequence);
            currentSequence = this.standSequence;
        }
        if (movementCounter > FRAME_LIMITER) {
            super.nextFrame();
            movementCounter = 0;
        } else {
            movementCounter++;
        }
    }

    /**
     * Changes the sequence to movement
     */
    public void moveForward(){
        if (currentSequence != this.movementSequence) {
            this.setFrameSequence(this.movementSequence);
            currentSequence = this.movementSequence;
        }
        if (movementCounter > FRAME_LIMITER) {
            super.nextFrame();
            movementCounter = 0;
        } else {
            movementCounter++;
        }
        super.move(1, 0);
    }

    /**
     * Changes the sequence to attack
     */
    public void attack(){
        if (currentSequence != this.attackSequence) {
            this.setFrameSequence(this.attackSequence);
            currentSequence = this.attackSequence;
        }
        if (movementCounter > FRAME_LIMITER) {
            super.nextFrame();
            movementCounter = 0;
        } else {
            movementCounter++;
        }
    }

    /**
     * Changes the sequence to retreat
     */
    public void retreat(){
        if (currentSequence != this.retreatSequence) {
            this.setFrameSequence(this.retreatSequence);
            currentSequence = this.retreatSequence;
        }
        if (movementCounter > FRAME_LIMITER) {
            super.nextFrame();
            movementCounter = 0;
        } else {
            movementCounter++;
        }
        super.move(-1, 0);
    }
}
